package chapt01.block;
// Block.java
// OpenGL SuperBible
// Demonstrates OpenGL Primitive GL_POINTS
// Program by Richard S. Wright Jr.

import java.nio.ByteBuffer;
import java.io.IOException;

import javax.media.opengl.GL2;
import com.jogamp.opengl.util.gl2.GLUT;
import com.jogamp.opengl.util.texture.spi.TGAImage;

public class Block
{
	static GLUT glut = new GLUT();
	
	// Keep track of effects step
	static int nStep = 0;
	
	// Lighting data
	static float lightAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f};
	static float lightDiffuse[] = {0.7f, 0.7f, 0.7f, 1.0f};
	static float lightSpecular[] = {0.9f, 0.9f, 0.9f};
	static float materialColor[] = {0.8f, 0.0f, 0.0f};
	static float vLightPos[] = {-80.0f, 120.0f, 100.0f, 0.0f};
	static float ground[][] = {
		{0.0f, -25.0f, 0.0f},
		{10.0f, -25.0f, 0.0f},
		{10.0f, -25.0f, -10.0f}
	};
	
	static int textures[] = new int[4];
	
	// This function does any needed initialization on the rendering context.
	protected static void setup(GL2 gl2, int width, int height)
	{
		TGAImage tgaImage;
		ByteBuffer pBytes;
		int nWidth, nHeight;
		int format;
		
		// Black background
		gl2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		
			gl2.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE);
			gl2.glGenTextures(4, textures, 0);
		
		// Load the texture objects
		try
		{
			tgaImage = TGAImage.read(Block.class.getResourceAsStream("floor.tga"));
			nWidth = tgaImage.getWidth();
			nHeight = tgaImage.getHeight();
			format = tgaImage.getGLFormat();
			pBytes = tgaImage.getData();
				
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[0]);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
			gl2.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB8, nWidth, nHeight, 0,
				format, GL2.GL_UNSIGNED_BYTE, pBytes);
			
			tgaImage = TGAImage.read(Block.class.getResourceAsStream("Block4.tga"));
			nWidth = tgaImage.getWidth();
			nHeight = tgaImage.getHeight();
			format = tgaImage.getGLFormat();
			pBytes = tgaImage.getData();
			
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[1]);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
			gl2.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB8, nWidth, nHeight, 0,
				format, GL2.GL_UNSIGNED_BYTE, pBytes);
			
			tgaImage = TGAImage.read(Block.class.getResourceAsStream("Block5.tga"));
			nWidth = tgaImage.getWidth();
			nHeight = tgaImage.getHeight();
			format = tgaImage.getGLFormat();
			pBytes = tgaImage.getData();
			
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[2]);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
			gl2.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB8, nWidth, nHeight, 0,
				format, GL2.GL_UNSIGNED_BYTE, pBytes);
			
			tgaImage = TGAImage.read(Block.class.getResourceAsStream("Block6.tga"));
			nWidth = tgaImage.getWidth();
			nHeight = tgaImage.getHeight();
			format = tgaImage.getGLFormat();
			pBytes = tgaImage.getData();
			
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[3]);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
			gl2.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
			gl2.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB8, nWidth, nHeight, 0,
				format, GL2.GL_UNSIGNED_BYTE, pBytes);
		}
		catch(IOException e)
		{
			
		}
	}
	
	// Called to draw scene
	protected static void render(GL2 gl2, int w, int h)
	{
		// Calculate new clipping volume
		float windowWidth;
		float windowHeight;
		
		// Prevent a divide by zero, when window is too short
		// (you can't make a window of zero width).
		if(h == 0)
			h = 1;
		
		// Keep the square square
		if(w <= h)
		{
			windowHeight = 100.0f * (float)h / (float)w;
			windowWidth = 100.0f;
		}
		else
		{
			windowWidth = 100.0f * (float)w / (float)h;
			windowHeight = 100.0f;
		}
		
		// Set the viewport to be the entire window
		gl2.glViewport(0, 0, w, h);
		
		gl2.glMatrixMode(GL2.GL_PROJECTION);
		gl2.glLoadIdentity();
		
		// Set the clipping volume
		gl2.glOrtho(-100.0f, windowWidth, -100.0f, windowHeight, -200.0f, 200.0f);
		
			gl2.glMatrixMode(GL2.GL_MODELVIEW);
			gl2.glLoadIdentity();
			
		gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, vLightPos, 0);
		
		gl2.glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
		gl2.glRotatef(330.0f, 0.0f, 1.0f, 0.0f);
		
		float mCubeTransform[] = new float[16];
		float pPlane[] = new float[4];
		
		// Clear the window with current clearing color
		gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
		gl2.glShadeModel(GL2.GL_SMOOTH);
		gl2.glEnable(GL2.GL_NORMALIZE);
		
		gl2.glPushMatrix();
		
		// Draw plane that the cube rests on
		gl2.glDisable(GL2.GL_LIGHTING);
		if(nStep == 5)
		{
			gl2.glColor3ub((byte)255, (byte)255, (byte)255);
			gl2.glEnable(GL2.GL_TEXTURE_2D);
			gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[0]);
			gl2.glBegin(GL2.GL_QUADS);
				gl2.glTexCoord2f(0.0f, 0.0f);
				gl2.glVertex3f(-100.0f, -25.3f, -100.0f);
				gl2.glTexCoord2f(0.0f, 1.0f);
				gl2.glVertex3f(-100.0f, -25.3f, 100.0f);
				gl2.glTexCoord2f(1.0f, 1.0f);
				gl2.glVertex3f(100.0f, -25.3f, 100.0f);
				gl2.glTexCoord2f(1.0f, 0.0f);
				gl2.glVertex3f(100.0f, -25.3f, -100.0f);
			gl2.glEnd();
		}
		else
		{
			gl2.glColor3f(0.0f, 0.0f, 0.9f); // Blue
			gl2.glBegin(GL2.GL_QUADS);
				gl2.glVertex3f(-100.0f, -25.3f, -100.0f);
				gl2.glVertex3f(-100.0f, -25.3f, 100.0f);
				gl2.glVertex3f(100.0f, -25.3f, 100.0f);
				gl2.glVertex3f(100.0f, -25.3f, -100.0f);
			gl2.glEnd();
		}
		
		// Set drawing color to Red
		gl2.glColor3f(1.0f, 0.0f, 0.0f);
		
		// Enable, disable lighting
		if(nStep > 2)
		{
			gl2.glEnable(GL2.GL_DEPTH_TEST);
			gl2.glDepthFunc(GL2.GL_LEQUAL);
			gl2.glEnable(GL2.GL_COLOR_MATERIAL);
			
			gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, lightAmbient, 0);
			gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, lightDiffuse, 0);
			gl2.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, lightSpecular, 0);
			gl2.glEnable(GL2.GL_LIGHTING);
			gl2.glEnable(GL2.GL_LIGHT0);
			gl2.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, lightSpecular, 0);
			gl2.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, materialColor, 0);
			gl2.glMateriali(GL2.GL_FRONT, GL2.GL_SHININESS, 128);
		}
		
		// Move the cube slightly forward and to the left
		gl2.glTranslatef(-10.0f, 0.0f, 10.0f);
		
		switch(nStep)
		{
			// Just draw the wire framed cube
			case 0:
				glut.glutWireCube(50.0f);
				break;
			
			// Same wire cube with hidden line removal simulated
			case 1:
				gl2.glBegin(GL2.GL_LINES);
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
					gl2.glVertex3f(25.0f, -25.0f, 25.0f);
					
					gl2.glVertex3f(25.0f, -25.0f, 25.0f);
					gl2.glVertex3f(-25.0f, -25.0f, 25.0f);
					
					gl2.glVertex3f(-25.0f, -25.0f, 25.0f);
					gl2.glVertex3f(-25.0f, 25.0f, 25.0f);
					
					gl2.glVertex3f(-25.0f, 25.0f, 25.0f);
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
				gl2.glEnd();
				
				// Top of cube
				gl2.glBegin(GL2.GL_LINES);
					// Front Face
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
					gl2.glVertex3f(25.0f, 25.0f, -25.0f);
					
					gl2.glVertex3f(25.0f, 25.0f, -25.0f);
					gl2.glVertex3f(-25.0f, 25.0f, -25.0f);
					
					gl2.glVertex3f(-25.0f, 25.0f, -25.0f);
					gl2.glVertex3f(-25.0f, 25.0f, 25.0f);
					
					gl2.glVertex3f(-25.0f, 25.0f, 25.0f);
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
				gl2.glEnd();
				
				// Last two segments for effect
				gl2.glBegin(GL2.GL_LINES);
					gl2.glVertex3f(25.0f, 25.0f, -25.0f);
					gl2.glVertex3f(25.0f, -25.0f, -25.0f);
					
					gl2.glVertex3f(25.0f, -25.0f, -25.0f);
					gl2.glVertex3f(25.0f, -25.0f, 25.0f);
				gl2.glEnd();
				
				break;
				
			// Uniform colored surface, looks 2D and goofey
			case 2:
				glut.glutSolidCube(50.0f);
				break;
			
			case 3:
				glut.glutSolidCube(50.0f);
				break;
				
			// Draw a shadow with some lighting
			case 4:
				gl2.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, mCubeTransform, 0);
				glut.glutSolidCube(50.0f);
				gl2.glPopMatrix();
				
				// Disable lighting, we'll just draw the shadow as black
				gl2.glDisable(GL2.GL_LIGHTING);
				
				gl2.glPushMatrix();
				
				M3D.getPlaneEquation(pPlane, ground[0], ground[1], ground[2]);
				M3D.makePlanarShadowMatrix(mCubeTransform, pPlane, vLightPos);
				// MakeShadowMatrix(ground, lightpos, cubeXform);
				gl2.glMultMatrixf(mCubeTransform, 0);
				
				gl2.glTranslatef(-10.0f, 0.0f, 10.0f);
				
				// Set drawing color to Black
				gl2.glColor3f(0.0f, 0.0f, 0.0f);
				
				glut.glutSolidCube(50.0f);
				break;
			
			case 5:
				gl2.glColor3ub((byte)255, (byte)255, (byte)255);
				gl2.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, mCubeTransform, 0);
				
				// Front Face (before rotation)
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[1]);
				gl2.glBegin(GL2.GL_QUADS);
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(25.0f, -25.0f, 25.0f);
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(-25.0f, -25.0f, 25.0f);
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(-25.0f, 25.0f, 25.0f);
				gl2.glEnd();
				
				// Top of cube
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[2]);
				gl2.glBegin(GL2.GL_QUADS);
					// Front Face
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(25.0f, 25.0f, -25.0f);
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(-25.0f, 25.0f, -25.0f);
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(-25.0f, 25.0f, 25.0f);
				gl2.glEnd();
				
				// Last two segments for effect
				gl2.glBindTexture(GL2.GL_TEXTURE_2D, textures[3]);
				gl2.glBegin(GL2.GL_QUADS);
					gl2.glTexCoord2f(1.0f, 1.0f);
					gl2.glVertex3f(25.0f, 25.0f, -25.0f);
					gl2.glTexCoord2f(1.0f, 0.0f);
					gl2.glVertex3f(25.0f, -25.0f, -25.0f);
					gl2.glTexCoord2f(0.0f, 0.0f);
					gl2.glVertex3f(25.0f, -25.0f, 25.0f);
					gl2.glTexCoord2f(0.0f, 1.0f);
					gl2.glVertex3f(25.0f, 25.0f, 25.0f);
				gl2.glEnd();
				
				gl2.glPopMatrix();
				
				// Disable lighting, we'll just draw the shadow as black
				gl2.glDisable(GL2.GL_LIGHTING);
				gl2.glDisable(GL2.GL_TEXTURE_2D);
				
				gl2.glPushMatrix();
				
				M3D.getPlaneEquation(pPlane, ground[0], ground[1], ground[2]);
				M3D.makePlanarShadowMatrix(mCubeTransform, pPlane, vLightPos);
				gl2.glMultMatrixf(mCubeTransform, 0);
				
				gl2.glTranslatef(-10.0f, 0.0f, 10.0f);
				
				// Set drawing color to black
				gl2.glColor3f(0.0f, 0.0f, 0.0f);
				glut.glutSolidCube(50.0f);
				break;
		}
	}
}